﻿namespace ImageProcessing.Draw_shaps.ShapesLib
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
   
    /// <summary>
    /// Class line
    /// </summary>
    public class Line
    {
        /// <summary>
        /// Line Points
        /// </summary>
        private Point pt1, pt2;
       
        /// <summary>
        /// a = slop, b = y depth // y = ax+b;
        /// </summary>
        private float a, b; 
       
        /// <summary>
        /// Line Fill Color
        /// </summary>
        private Color fillColor;
        
        /// <summary>
        /// Line Pen Color
        /// </summary>
        private Color penColor;
       
        /// <summary>
        /// Line Pen Width
        /// </summary>
        private float penWidth;

        /// <summary>
        /// Initializes a new instance of the Line class.
        /// </summary>
        public Line()
        {
            this.PenColor = Color.Black;
            this.PenWidth = 4;
        }

        /// <summary>
        /// Gets or sets the p2.
        /// </summary>
        /// <value>
        /// The p2.
        /// </value>
        public int P2X
        {
            get { return this.pt2.X; }
            set { this.pt2.X = value; }
        }

        /// <summary>
        /// Gets or sets the p2.
        /// </summary>
        /// <value>
        /// The p2.
        /// </value>
        public int P2Y
        {
            get { return this.pt2.Y; }
            set { this.pt2.Y = value; }
        }

        /// <summary>
        /// Gets or sets the p2.
        /// </summary>
        /// <value>
        /// The p2.
        /// </value>
        public int P1X
        {
            get { return this.pt1.X; }
            set { this.pt1.X = value; }
        }

        /// <summary>
        /// Gets or sets the p2.
        /// </summary>
        /// <value>
        /// The p1.
        /// </value>
        public int P1Y
        {
            get { return this.pt1.Y; }
            set { this.pt1.Y = value; }
        }
       
        /// <summary>
        /// Gets or sets the color of the fill.
        /// </summary>
        /// <value>
        /// The color of the fill.
        /// </value>
        public Color FillColor
        {
            get { return this.fillColor; }
            set { this.fillColor = value; }
        }
        
        /// <summary>
        /// Gets or sets the color of the pen.
        /// </summary>
        /// <value>
        /// The color of the pen.
        /// </value>
        public Color PenColor
        {
            get { return this.penColor; }
            set { this.penColor = value; }
        }
       
        /// <summary>
        /// Gets or sets the width of the pen.
        /// </summary>
        /// <value>
        /// The width of the pen.
        /// </value>
        public float PenWidth
        {
            get { return this.penWidth; }
            set { this.penWidth = value; }
        }

        /// <summary>
        /// Join 2 lines l1 and l2.
        /// </summary>
        /// <param name="l1">The l1.</param>
        /// <param name="l2">The l2.</param>
        /// <returns> the new line </returns>
        public static Line Join2lines(Line l1, Line l2)
        {
            Line ln = new Line();
            ln.pt2 = l1.pt2;
            ln.pt1 = l2.pt1;
            return ln;
        }

        /// <summary>
        /// Draws the specified g.
        /// </summary>
        /// <param name="g">The g.</param>
        public void Draw(Graphics g)
        {
            Pen myPen = new Pen(this.PenColor, this.PenWidth);
            g.DrawLine(myPen, this.pt1, this.pt2);
        }

        /// <summary>
        /// Breaks the line.
        /// </summary>
        /// <param name="breakPoint">The break point.</param>
        /// <param name="l1">The l1.</param>
        /// <param name="l2">The l2.</param>
        public void BreakLine(Point breakPoint, Line l1, Line l2)
        {
            if (breakPoint.X >= this.pt1.X)
            {
                l1.pt1 = this.pt1;
                l1.pt2 = breakPoint;
                l2.pt1 = breakPoint;
                l2.pt2 = this.pt2;
            }
            else if (breakPoint.X >= this.pt2.X)
            {
                l1.pt1 = this.pt2;
                l1.pt2 = breakPoint;
                l2.pt1 = breakPoint;
                l2.pt2 = this.pt1;
            }
            else
            {
                MessageBox.Show(" a ?? ");
            }
        }

        /// <summary>
        /// Determines whether [is the breaked line] [the specified breakedpoint].
        /// </summary>
        /// <param name="breakedpoint">The breakedpoint.</param>
        /// <param name="tolerance">The tolerance.</param>
        /// <returns>
        ///   <c>true</c> if [is the breaked line] [the specified breakedpoint]; otherwise, <c>false</c>.
        /// </returns>
        public bool IsTheBreakedLine(Point breakedpoint, float tolerance)
        {
            return this.IsPointOnLine(this.pt1, this.pt2, breakedpoint, tolerance);
        }

        /// <summary>
        /// Determines whether [is point on line] [the specified line point A].
        /// </summary>
        /// <param name="linePointA">The line point A.</param>
        /// <param name="linePointB">The line point B.</param>
        /// <param name="point">The point.</param>
        /// <param name="tolerance">The tolerance.</param>
        /// <returns>
        ///   <c>true</c> if [is point on line] [the specified line point A]; otherwise, <c>false</c>.
        /// </returns>
        public bool IsPointOnLine(Point linePointA, Point linePointB, Point point, float tolerance)
        {
            float x = point.X;
            float y = point.Y;
            float x1 = linePointA.X;
            float y1 = linePointA.Y;
            float x2 = linePointB.X;
            float y2 = linePointB.Y;

            if (this.Is_between(x, x1, x2, tolerance) && this.Is_between(y, y1, y2, tolerance))
            {
                if (Math.Abs(x2 - x1) <= tolerance)
                {
                    return true;
                }

                float m = (y2 - y1) / (x2 - x1);
                float c = -(m * x1) + y1;

                return Math.Abs(y - ((m * x) + c)) <= tolerance;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// Is_betweens the specified x.
        /// </summary>
        /// <param name="x">The x.</param>
        /// <param name="bound1">The bound1.</param>
        /// <param name="bound2">The bound2.</param>
        /// <param name="tolerance">The tolerance.</param>
        /// <returns> true if the point between the two bounds</returns>
        public bool Is_between(float x, float bound1, float bound2, float tolerance)
        {
            return ((x >= (bound1 - tolerance)) && (x <= (bound2 + tolerance))) ||
               ((x >= (bound2 - tolerance)) && (x <= (bound1 + tolerance)));
        }

        /// <summary>
        /// Updates the line eqn.
        /// </summary>
        public void UpdateLineEqn()
        {
            try
            {
                this.a = (this.pt2.Y - this.pt1.Y) / (this.pt2.X - this.pt1.X);
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
            }

            this.b = this.pt1.Y - (this.a * this.pt1.X);
        }

        /// <summary>
        /// Gets the Y.
        /// </summary>
        /// <param name="x">The x.</param>
        /// <returns> Value of Y of the specific X</returns>
        public float GetY(float x)
        {
            this.UpdateLineEqn();
            float y = (this.a * x) + this.b;
            return y;
        }
    }
}
